(十)Dubbo使用多协议(hessian、rest、dubbo) | 您所在的位置:网站首页 › dubbo application › (十)Dubbo使用多协议(hessian、rest、dubbo) |
Dubbo是支持多种协议的,这里我会 演示 dubbo(默认)、hessian、rest 这三种协议。文章代码贴的比较多,代码已经上传到GitHub,见文末。 假如我有这样一个场景: OrderService 接口有两个实现类,其中一个 OrderServiceImpl 获取的数据较小,我想通过dubbo协议调用;而另外一个 OrderServiceImpl2 获取的数据较大,我想通过 hessian协议调用,或者我想直接通过Http调用provider的接口。 这要如何配置呢? 下面来研究一下这几种协议的使用。 TODO:可以使用jmh压测不同协议传输不同的数据量,进行性能对比 项目结构: 父类pom,引入协议需要的依赖: dubbo-samples-xml-api dubbo-samples-xml-provider dubbo-samples-xml-consumer Demo project for Spring 1.8 1.8 2.7.13 4.3.16.RELEASE 4.12 8.0.53 1.1.0.Final 4.2.0.Final org.springframework spring-framework-bom ${spring.version} pom import org.apache.dubbo dubbo-bom ${dubbo.version} pom import org.apache.dubbo dubbo-dependencies-zookeeper ${dubbo.version} pom junit junit ${junit.version} test javax.validation validation-api ${validation-api.version} org.hibernate hibernate-validator ${hibernate-validator.version} org.apache.tomcat.embed tomcat-embed-core ${tomcat.version} 1、新建api项目新建dubbo-samples-xml-api项目 pom.xml: org.apache.dubbo dubbo-rpc-rest org.projectlombok lombok 1.18.12定义接口: OrderRESTService: public interface OrderRESTService { Order getOrderInfo(Long id); }OrderRESTService2,一个标准的 JAX-RS rest服务: @Consumes({MediaType.APPLICATION_JSON}) @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) @Path("order2") public interface OrderRESTService2 { @GET @Path("{id : \\d+}") Order getOrderInfo(@PathParam("id") Long id); }OrderService:普通接口 public interface OrderService { List getOrderInfo(long orderId); }Order:实体类 @Data @NoArgsConstructor @AllArgsConstructor public class Order implements Serializable { private static final long serialVersionUID = -3757842094691885448L; Long orderId; String orderName; } 2、创建provider创建一个dubbo-samples-xml-provider 项目。 pom.xml: com.dubbo dubbo-samples-xml-api 0.0.1-SNAPSHOT org.springframework spring-web org.springframework spring-context org.apache.dubbo dubbo junit junit org.apache.tomcat.embed tomcat-embed-core org.hibernate hibernate-validator org.apache.dubbo dubbo-rpc-rest org.apache.dubbo dubbo-registry-zookeeper org.apache.dubbo dubbo-rpc-hessian创建四个实现类: 其中 OrderServiceImpl、OrderServiceImpl2 均实现 OrderService 接口,具体代码如下: OrderServiceImpl: @Service("orderServiceImpl") @Slf4j public class OrderServiceImpl implements OrderService { @Override public List getOrderInfo(long orderId) { log.info("OrderServiceImpl方法"); log.info("request from consumer: {}", RpcContext.getContext().getRemoteAddress()); log.info("protocol: {}",RpcContext.getContext().getProtocol()); log.info("response from provider: {}",RpcContext.getContext().getLocalAddress()); List list = new ArrayList(); Order order1 = new Order(); order1.setOrderId(199L); order1.setOrderName("MacBook Pro 13"); Order order2 = new Order(); order2.setOrderId(200L); order2.setOrderName("RTX 2060"); list.add(order1); list.add(order2); return list; } }OrderServiceImpl2: /** * @author 醋酸菌HaC | WebSite📶 : https://rain.baimuxym.cn * @site * @date 2021/11/17 * @Description 这是个复杂大对象,用于测试传输大包 */ @Service("orderServiceImpl2") @Slf4j public class OrderServiceImpl2 implements OrderService { @Override public List getOrderInfo(long orderId) { log.info("OrderServiceImpl2方法"); log.info("request from consumer: {}", RpcContext.getContext().getRemoteAddress()); log.info("protocol: {}",RpcContext.getContext().getProtocol()); log.info("response from provider: {}",RpcContext.getContext().getLocalAddress()); List list = new ArrayList(); for (int i = 10; i这里声明了三种协议,协议注意不同的端口,server="tomcat" 表示使用的是内部tomcat。 Provider启动类: public class Provider { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/dubbo-provider.xml"}); context.start(); System.out.println("provider service start ......"); new CountDownLatch(1).await(); } } 3、创建consumer创建dubbo-samples-xml-consumer项目。 pom: com.dubbo dubbo-samples-xml-api 0.0.1-SNAPSHOT compile org.apache.dubbo dubbo org.apache.dubbo dubbo-dependencies-zookeeper pom org.springframework spring-web org.hibernate hibernate-validator org.apache.dubbo dubbo-rpc-rest org.apache.dubbo dubbo-registry-zookeeper org.apache.dubbo dubbo-rpc-hessiandubbo-consumer.xml 配置类: Consumer启动类: /** * @author 醋酸菌HaC | WebSite📶 : https://rain.baimuxym.cn * @date 2021/11/22 * @Description consumer启动类 */ public class Consumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/dubbo-consumer.xml"}); context.start(); System.out.println("consumer start....."); // dubbo OrderService orderService1 = context.getBean("orderServiceImpl", OrderService.class); // hessian OrderService orderService2 = context.getBean("orderServiceImpl2", OrderService.class); // rest OrderRESTService2 orderRESTService2 = context.getBean("orderRESTService2", OrderRESTService2.class); while (true) { System.in.read(); RpcContext rpcContext = RpcContext.getContext(); System.out.println("SUCCESS: got order list " + orderService1.getOrderInfo(1L)); System.out.println("SUCCESS: got order list" + orderService2.getOrderInfo(1L)); System.out.println("SUCCESS: got order " + orderRESTService2.getOrderInfo(1L)); // rest String port = "7777"; getOrder("http://localhost:" + port + "/services/order/2"); } } /** * 走http调用 * @param url */ private static void getOrder(String url) { Client client = ClientBuilder.newClient(); WebTarget target = client.target(url); Response response = target.request().get(); try { if (response.getStatus() != 200) { throw new RuntimeException("Failed with HTTP error code : " + response.getStatus()); } System.out.println("SUCCESS: got result: " + response.readEntity(Order.class)); } finally { response.close(); client.close(); } } } 4、测试执行 provider 测试类,打开dubbo-admin 项目(dubbo官方的可视化面板,需要自行搭建),可以看到有四个提供接口: 点击某个接口,可以看到详细的信息: 启动consumer测试类,可以看到日志: consumer日志: SUCCESS: got order list [Order(orderId=199, orderName=MacBook Pro 13), Order(orderId=200, orderName=RTX 2060)] SUCCESS: got order list[Order(orderId=10, orderName=MacBook Pro 10), Order(orderId=11, orderName=MacBook Pro 11), Order(orderId=12, orderName=MacBook Pro 12), Order(orderId=13, orderName=MacBook Pro 13), Order(orderId=14, orderName=MacBook Pro 14), Order(orderId=15, orderName=MacBook Pro 15), Order(orderId=16, orderName=MacBook Pro 16), Order(orderId=17, orderName=MacBook Pro 17), Order(orderId=18, orderName=MacBook Pro 18), Order(orderId=19, orderName=MacBook Pro 19), Order(orderId=20, orderName=MacBook Pro 20)] SUCCESS: got order Order(orderId=1, orderName=MacBook Pro) SUCCESS: got result: Order(orderId=2, orderName=MacBook Air2)provider日志: # 这里是dubbo协议调用 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: OrderServiceImpl方法 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: request from consumer: /172.16.44.48:54311 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: protocol: null 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: response from provider: 172.16.44.48:20883 # 这里是hessian协议调用 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: OrderServiceImpl2方法 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: request from consumer: 172.16.44.48:54314 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: protocol: dubbo 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: response from provider: 172.16.44.48:8888 # 这里是rest协议调用 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: 这是在接口上声明的rest 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: request from consumer: 172.16.44.48:54315 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: protocol: dubbo 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: response from provider: 172.16.44.48:7777 # 这里是http协议调用 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: 这是在实现类上声明的rest 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: request from consumer: 127.0.0.1:54316 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: protocol: dubbo 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: response from provider: 172.16.44.48:7777在dubbo-admin可以看到有三个消费者(rest、hessian、dubbo 各一个协议的消费者,第四个是http直连的): dubbo支持rest(dubbo集成了JAX-RS)在使用上,这里和spring有异曲同工之妙,简单使用几个JAX-RS注解就可以使用了,如: @Path("users") public class UserServiceImpl implements UserService { @POST @Path("register") @Consumes({MediaType.APPLICATION_JSON}) public void registerUser(User user) { // save the user... } }@Path("users"):指定访问UserService的URL相对路径是/users,即http://localhost:8080/users @Path("register"):指定访问registerUser()方法的URL相对路径是/register,再结合上一个@Path为UserService指定的路径,则调用UserService.register()的完整路径为http://localhost:8080/users/register @POST:指定访问registerUser()用HTTP POST方法 @Consumes({MediaType.APPLICATION_JSON}):指定registerUser()接收JSON格式的数据。REST框架会自动将JSON数据反序列化为User对象 然后在配置中声明需要暴露的服务接口即可: 5.2、踩坑:使用 rest 协议的时候,启动consumer 发现报错: You must use at least one, but no more than one http method annotation on: public abstract原因是 实现类使用 @Path、@Consumes、@Produces 注解: @Service("orderRESTServiceImpl") @Path("provider") @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) public class OrderRESTServiceImpl implements OrderRESTService {consumer.xml 又配置了: 使用了JAX-RS 的注解,本来就提供REST服务,所以就会出现两个REST,提示报错。 解决方法: 使用JAX-RS的注解到接口上,而不是实现类 使用http直连的方法访问即可,rest协议可以直接使用 http 访问那 Annotation放在接口类还是实现类? 在一般应用中, 建议放在实现类,便于维护,又不用污染接口,万一该接口有多个实现类就.... 如果接口和实现类都同时添加了annotation,则实现类的annotation配置会生效,接口上的annotation被直接忽略。 当然你都放在实现类了,在consumer的配置文件,就不要使用 protocol="rest" 这种方式调用了,直接使用http连接就可以了。 5.3、rest、hessian这两个协议需要依赖 servlet 容器,当然你也可以使用外部的servlet容器,只需要在你的web.xml配置: contextConfigLocation classpath:/spring/dubbo-provider-rest.xml org.apache.dubbo.remoting.http.servlet.BootstrapListener org.springframework.web.context.ContextLoaderListener dispatcher org.apache.dubbo.remoting.http.servlet.DispatcherServlet 1 dispatcher /services/*在配置文件中声明: contextpath 必须要和 web.xml 配置的 url-pattern 一致 端口也必须要和外部servlet容器一致 未来TODO: 参考: 使用 rest 协议:https://dangdangdotcom.github.io/dubbox/rest.html |
CopyRight 2018-2019 实验室设备网 版权所有 |